home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / lpr / RCS / lpr.c,v < prev    next >
Encoding:
Text File  |  1992-04-16  |  14.3 KB  |  711 lines

  1. head     1.1;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    shirriff:1.1; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.1
  10. date     88.11.23.10.31.50;  author rab;  state Exp;
  11. branches ;
  12. next     ;
  13.  
  14.  
  15. desc
  16. @@
  17.  
  18.  
  19.  
  20. 1.1
  21. log
  22. @Initial revision
  23. @
  24. text
  25. @/*
  26.  * Copyright (c) 1983 Regents of the University of California.
  27.  * All rights reserved.
  28.  *
  29.  * Redistribution and use in source and binary forms are permitted
  30.  * provided that this notice is preserved and that due credit is given
  31.  * to the University of California at Berkeley. The name of the University
  32.  * may not be used to endorse or promote products derived from this
  33.  * software without specific prior written permission. This software
  34.  * is provided ``as is'' without express or implied warranty.
  35.  */
  36.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@@(#) Copyright (c) 1983 Regents of the University of California.\n\
  40.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. static char sccsid[] = "@@(#)lpr.c    5.3 (Berkeley) 5/5/88";
  45. #endif /* not lint */
  46.  
  47. /*
  48.  *      lpr -- off line print
  49.  *
  50.  * Allows multiple printers and printers on remote machines by
  51.  * using information from a printer data base.
  52.  */
  53.  
  54. #include <stdio.h>
  55. #include <sys/types.h>
  56. #include <sys/file.h>
  57. #include <sys/stat.h>
  58. #include <pwd.h>
  59. #include <grp.h>
  60. #include <signal.h>
  61. #include <ctype.h>
  62. #include <syslog.h>
  63. #include "lp.local.h"
  64.  
  65. char    *tfname;        /* tmp copy of cf before linking */
  66. char    *cfname;        /* daemon control files, linked from tf's */
  67. char    *dfname;        /* data files */
  68.  
  69. int    nact;            /* number of jobs to act on */
  70. int    tfd;            /* control file descriptor */
  71. int     mailflg;        /* send mail */
  72. int    qflag;            /* q job, but don't exec daemon */
  73. char    format = 'f';        /* format char for printing files */
  74. int    rflag;            /* remove files upon completion */    
  75. int    sflag;            /* symbolic link flag */
  76. int    inchar;            /* location to increment char in file names */
  77. int     ncopies = 1;        /* # of copies to make */
  78. int    iflag;            /* indentation wanted */
  79. int    indent;            /* amount to indent */
  80. int    hdr = 1;        /* print header or not (default is yes) */
  81. int     userid;            /* user id */
  82. char    *person;        /* user name */
  83. char    *title;            /* pr'ing title */
  84. char    *fonts[4];        /* troff font names */
  85. char    *width;            /* width for versatec printing */
  86. char    host[32];        /* host name */
  87. char    *class = host;        /* class title on header page */
  88. char    *jobname;        /* job name on header page */
  89. char    *name;            /* program name */
  90. char    *printer;        /* printer name */
  91. struct    stat statb;
  92.  
  93. int    MX;            /* maximum number of blocks to copy */
  94. int    MC;            /* maximum number of copies allowed */
  95. int    DU;            /* daemon user-id */
  96. char    *SD;            /* spool directory */
  97. char    *LO;            /* lock file name */
  98. char    *RG;            /* restrict group */
  99. short    SC;            /* suppress multiple copies */
  100.  
  101. char    *getenv();
  102. char    *rindex();
  103. char    *linked();
  104. int    cleanup();
  105.  
  106. /*ARGSUSED*/
  107. main(argc, argv)
  108.     int argc;
  109.     char *argv[];
  110. {
  111.     extern struct passwd *getpwuid();
  112.     struct passwd *pw;
  113.     struct group *gptr;
  114.     extern char *itoa();
  115.     register char *arg, *cp;
  116.     char buf[BUFSIZ];
  117.     int i, f;
  118.     struct stat stb;
  119.  
  120.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  121.         signal(SIGHUP, cleanup);
  122.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  123.         signal(SIGINT, cleanup);
  124.     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  125.         signal(SIGQUIT, cleanup);
  126.     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  127.         signal(SIGTERM, cleanup);
  128.  
  129.     name = argv[0];
  130.     gethostname(host, sizeof (host));
  131.     openlog("lpd", 0, LOG_LPR);
  132.  
  133.     while (argc > 1 && argv[1][0] == '-') {
  134.         argc--;
  135.         arg = *++argv;
  136.         switch (arg[1]) {
  137.  
  138.         case 'P':        /* specifiy printer name */
  139.             if (arg[2])
  140.                 printer = &arg[2];
  141.             else if (argc > 1) {
  142.                 argc--;
  143.                 printer = *++argv;
  144.             }
  145.             break;
  146.  
  147.         case 'C':        /* classification spec */
  148.             hdr++;
  149.             if (arg[2])
  150.                 class = &arg[2];
  151.             else if (argc > 1) {
  152.                 argc--;
  153.                 class = *++argv;
  154.             }
  155.             break;
  156.  
  157.         case 'J':        /* job name */
  158.             hdr++;
  159.             if (arg[2])
  160.                 jobname = &arg[2];
  161.             else if (argc > 1) {
  162.                 argc--;
  163.                 jobname = *++argv;
  164.             }
  165.             break;
  166.  
  167.         case 'T':        /* pr's title line */
  168.             if (arg[2])
  169.                 title = &arg[2];
  170.             else if (argc > 1) {
  171.                 argc--;
  172.                 title = *++argv;
  173.             }
  174.             break;
  175.  
  176.         case 'l':        /* literal output */
  177.         case 'p':        /* print using ``pr'' */
  178.         case 't':        /* print troff output (cat files) */
  179.         case 'n':        /* print ditroff output */
  180.         case 'd':        /* print tex output (dvi files) */
  181.         case 'g':        /* print graph(1G) output */
  182.         case 'c':        /* print cifplot output */
  183.         case 'v':        /* print vplot output */
  184.             format = arg[1];
  185.             break;
  186.  
  187.         case 'f':        /* print fortran output */
  188.             format = 'r';
  189.             break;
  190.  
  191.         case '4':        /* troff fonts */
  192.         case '3':
  193.         case '2':
  194.         case '1':
  195.             if (argc > 1) {
  196.                 argc--;
  197.                 fonts[arg[1] - '1'] = *++argv;
  198.             }
  199.             break;
  200.  
  201.         case 'w':        /* versatec page width */
  202.             width = arg+2;
  203.             break;
  204.  
  205.         case 'r':        /* remove file when done */
  206.             rflag++;
  207.             break;
  208.  
  209.         case 'm':        /* send mail when done */
  210.             mailflg++;
  211.             break;
  212.  
  213.         case 'h':        /* toggle want of header page */
  214.             hdr = !hdr;
  215.             break;
  216.  
  217.         case 's':        /* try to link files */
  218.             sflag++;
  219.             break;
  220.  
  221.         case 'q':        /* just q job */
  222.             qflag++;
  223.             break;
  224.  
  225.         case 'i':        /* indent output */
  226.             iflag++;
  227.             indent = arg[2] ? atoi(&arg[2]) : 8;
  228.             break;
  229.  
  230.         case '#':        /* n copies */
  231.             if (isdigit(arg[2])) {
  232.                 i = atoi(&arg[2]);
  233.                 if (i > 0)
  234.                     ncopies = i;
  235.             }
  236.         }
  237.     }
  238.     if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
  239.         printer = DEFLP;
  240.     chkprinter(printer);
  241.     if (SC && ncopies > 1)
  242.         fatal("multiple copies are not allowed");
  243.     if (MC > 0 && ncopies > MC)
  244.         fatal("only %d copies are allowed", MC);
  245.     /*
  246.      * Get the identity of the person doing the lpr using the same
  247.      * algorithm as lprm. 
  248.      */
  249.     userid = getuid();
  250.     if ((pw = getpwuid(userid)) == NULL)
  251.         fatal("Who are you?");
  252.     person = pw->pw_name;
  253.     /*
  254.      * Check for restricted group access.
  255.      */
  256.     if (RG != NULL) {
  257.         if ((gptr = getgrnam(RG)) == NULL)
  258.             fatal("Restricted group specified incorrectly");
  259.         if (gptr->gr_gid != getgid()) {
  260.             while (*gptr->gr_mem != NULL) {
  261.                 if ((strcmp(person, *gptr->gr_mem)) == 0)
  262.                     break;
  263.                 gptr->gr_mem++;
  264.             }
  265.             if (*gptr->gr_mem == NULL)
  266.                 fatal("Not a member of the restricted group");
  267.         }
  268.     }
  269.     /*
  270.      * Check to make sure queuing is enabled if userid is not root.
  271.      */
  272.     (void) sprintf(buf, "%s/%s", SD, LO);
  273.     if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
  274.         fatal("Printer queue is disabled");
  275.     /*
  276.      * Initialize the control file.
  277.      */
  278.     mktemps();
  279.     tfd = nfile(tfname);
  280.     (void) fchown(tfd, DU, -1);    /* owned by daemon for protection */
  281.     card('H', host);
  282.     card('P', person);
  283.     if (hdr) {
  284.         if (jobname == NULL) {
  285.             if (argc == 1)
  286.                 jobname = "stdin";
  287.             else
  288.                 jobname = (arg = rindex(argv[1], '/')) ? arg+1 : argv[1];
  289.         }
  290.         card('J', jobname);
  291.         card('C', class);
  292.         card('L', person);
  293.     }
  294.     if (iflag)
  295.         card('I', itoa(indent));
  296.     if (mailflg)
  297.         card('M', person);
  298.     if (format == 't' || format == 'n' || format == 'd')
  299.         for (i = 0; i < 4; i++)
  300.             if (fonts[i] != NULL)
  301.                 card('1'+i, fonts[i]);
  302.     if (width != NULL)
  303.         card('W', width);
  304.  
  305.     /*
  306.      * Read the files and spool them.
  307.      */
  308.     if (argc == 1)
  309.         copy(0, " ");
  310.     else while (--argc) {
  311.         if ((f = test(arg = *++argv)) < 0)
  312.             continue;    /* file unreasonable */
  313.  
  314.         if (sflag && (cp = linked(arg)) != NULL) {
  315.             (void) sprintf(buf, "%d %d", statb.st_dev, statb.st_ino);
  316.             card('S', buf);
  317.             if (format == 'p')
  318.                 card('T', title ? title : arg);
  319.             for (i = 0; i < ncopies; i++)
  320.                 card(format, &dfname[inchar-2]);
  321.             card('U', &dfname[inchar-2]);
  322.             if (f)
  323.                 card('U', cp);
  324.             card('N', arg);
  325.             dfname[inchar]++;
  326.             nact++;
  327.             continue;
  328.         }
  329.         if (sflag)
  330.             printf("%s: %s: not linked, copying instead\n", name, arg);
  331.         if ((i = open(arg, O_RDONLY)) < 0) {
  332.             printf("%s: cannot open %s\n", name, arg);
  333.             continue;
  334.         }
  335.         copy(i, arg);
  336.         (void) close(i);
  337.         if (f && unlink(arg) < 0)
  338.             printf("%s: %s: not removed\n", name, arg);
  339.     }
  340.  
  341.     if (nact) {
  342.         (void) close(tfd);
  343.         tfname[inchar]--;
  344.         /*
  345.          * Touch the control file to fix position in the queue.
  346.          */
  347.         if ((tfd = open(tfname, O_RDWR)) >= 0) {
  348.             char c;
  349.  
  350.             if (read(tfd, &c, 1) == 1 && lseek(tfd, 0L, 0) == 0 &&
  351.                 write(tfd, &c, 1) != 1) {
  352.                 printf("%s: cannot touch %s\n", name, tfname);
  353.                 tfname[inchar]++;
  354.                 cleanup();
  355.             }
  356.             (void) close(tfd);
  357.         }
  358.         if (link(tfname, cfname) < 0) {
  359.             printf("%s: cannot rename %s\n", name, cfname);
  360.             tfname[inchar]++;
  361.             cleanup();
  362.         }
  363.         unlink(tfname);
  364.         if (qflag)        /* just q things up */
  365.             exit(0);
  366.         if (!startdaemon(printer))
  367.             printf("jobs queued, but cannot start daemon.\n");
  368.         exit(0);
  369.     }
  370.     cleanup();
  371.     /* NOTREACHED */
  372. }
  373.  
  374. /*
  375.  * Create the file n and copy from file descriptor f.
  376.  */
  377. copy(f, n)
  378.     int f;
  379.     char n[];
  380. {
  381.     register int fd, i, nr, nc;
  382.     char buf[BUFSIZ];
  383.  
  384.     if (format == 'p')
  385.         card('T', title ? title : n);
  386.     for (i = 0; i < ncopies; i++)
  387.         card(format, &dfname[inchar-2]);
  388.     card('U', &dfname[inchar-2]);
  389.     card('N', n);
  390.     fd = nfile(dfname);
  391.     nr = nc = 0;
  392.     while ((i = read(f, buf, BUFSIZ)) > 0) {
  393.         if (write(fd, buf, i) != i) {
  394.             printf("%s: %s: temp file write error\n", name, n);
  395.             break;
  396.         }
  397.         nc += i;
  398.         if (nc >= BUFSIZ) {
  399.             nc -= BUFSIZ;
  400.             nr++;
  401.             if (MX > 0 && nr > MX) {
  402.                 printf("%s: %s: copy file is too large\n", name, n);
  403.                 break;
  404.             }
  405.         }
  406.     }
  407.     (void) close(fd);
  408.     if (nc==0 && nr==0) 
  409.         printf("%s: %s: empty input file\n", name, f ? n : "stdin");
  410.     else
  411.         nact++;
  412. }
  413.  
  414. /*
  415.  * Try and link the file to dfname. Return a pointer to the full
  416.  * path name if successful.
  417.  */
  418. char *
  419. linked(file)
  420.     register char *file;
  421. {
  422.     register char *cp;
  423.     static char buf[BUFSIZ];
  424.  
  425.     if (*file != '/') {
  426.         if (getwd(buf) == NULL)
  427.             return(NULL);
  428.         while (file[0] == '.') {
  429.             switch (file[1]) {
  430.             case '/':
  431.                 file += 2;
  432.                 continue;
  433.             case '.':
  434.                 if (file[2] == '/') {
  435.                     if ((cp = rindex(buf, '/')) != NULL)
  436.                         *cp = '\0';
  437.                     file += 3;
  438.                     continue;
  439.                 }
  440.             }
  441.             break;
  442.         }
  443.         strcat(buf, "/");
  444.         strcat(buf, file);
  445.         file = buf;
  446.     }
  447.     return(symlink(file, dfname) ? NULL : file);
  448. }
  449.  
  450. /*
  451.  * Put a line into the control file.
  452.  */
  453. card(c, p2)
  454.     register char c, *p2;
  455. {
  456.     char buf[BUFSIZ];
  457.     register char *p1 = buf;
  458.     register int len = 2;
  459.  
  460.     *p1++ = c;
  461.     while ((c = *p2++) != '\0') {
  462.         *p1++ = c;
  463.         len++;
  464.     }
  465.     *p1++ = '\n';
  466.     write(tfd, buf, len);
  467. }
  468.  
  469. /*
  470.  * Create a new file in the spool directory.
  471.  */
  472. nfile(n)
  473.     char *n;
  474. {
  475.     register f;
  476.     int oldumask = umask(0);        /* should block signals */
  477.  
  478.     f = creat(n, FILMOD);
  479.     (void) umask(oldumask);
  480.     if (f < 0) {
  481.         printf("%s: cannot create %s\n", name, n);
  482.         cleanup();
  483.     }
  484.     if (fchown(f, userid, -1) < 0) {
  485.         printf("%s: cannot chown %s\n", name, n);
  486.         cleanup();
  487.     }
  488.     if (++n[inchar] > 'z') {
  489.         if (++n[inchar-2] == 't') {
  490.             printf("too many files - break up the job\n");
  491.             cleanup();
  492.         }
  493.         n[inchar] = 'A';
  494.     } else if (n[inchar] == '[')
  495.         n[inchar] = 'a';
  496.     return(f);
  497. }
  498.  
  499. /*
  500.  * Cleanup after interrupts and errors.
  501.  */
  502. cleanup()
  503. {
  504.     register i;
  505.  
  506.     signal(SIGHUP, SIG_IGN);
  507.     signal(SIGINT, SIG_IGN);
  508.     signal(SIGQUIT, SIG_IGN);
  509.     signal(SIGTERM, SIG_IGN);
  510.     i = inchar;
  511.     if (tfname)
  512.         do
  513.             unlink(tfname);
  514.         while (tfname[i]-- != 'A');
  515.     if (cfname)
  516.         do
  517.             unlink(cfname);
  518.         while (cfname[i]-- != 'A');
  519.     if (dfname)
  520.         do {
  521.             do
  522.                 unlink(dfname);
  523.             while (dfname[i]-- != 'A');
  524.             dfname[i] = 'z';
  525.         } while (dfname[i-2]-- != 'd');
  526.     exit(1);
  527. }
  528.  
  529. /*
  530.  * Test to see if this is a printable file.
  531.  * Return -1 if it is not, 0 if its printable, and 1 if
  532.  * we should remove it after printing.
  533.  */
  534. test(file)
  535.     char *file;
  536. {
  537.     struct exec execb;
  538.     register int fd;
  539.     register char *cp;
  540.  
  541.     if (access(file, 4) < 0) {
  542.         printf("%s: cannot access %s\n", name, file);
  543.         return(-1);
  544.     }
  545.     if (stat(file, &statb) < 0) {
  546.         printf("%s: cannot stat %s\n", name, file);
  547.         return(-1);
  548.     }
  549.     if ((statb.st_mode & S_IFMT) == S_IFDIR) {
  550.         printf("%s: %s is a directory\n", name, file);
  551.         return(-1);
  552.     }
  553.     if (statb.st_size == 0) {
  554.         printf("%s: %s is an empty file\n", name, file);
  555.         return(-1);
  556.      }
  557.     if ((fd = open(file, O_RDONLY)) < 0) {
  558.         printf("%s: cannot open %s\n", name, file);
  559.         return(-1);
  560.     }
  561.     if (read(fd, &execb, sizeof(execb)) == sizeof(execb))
  562.         switch(execb.a_magic) {
  563.         case A_MAGIC1:
  564.         case A_MAGIC2:
  565.         case A_MAGIC3:
  566. #ifdef A_MAGIC4
  567.         case A_MAGIC4:
  568. #endif
  569.             printf("%s: %s is an executable program", name, file);
  570.             goto error1;
  571.  
  572.         case ARMAG:
  573.             printf("%s: %s is an archive file", name, file);
  574.             goto error1;
  575.         }
  576.     (void) close(fd);
  577.     if (rflag) {
  578.         if ((cp = rindex(file, '/')) == NULL) {
  579.             if (access(".", 2) == 0)
  580.                 return(1);
  581.         } else {
  582.             *cp = '\0';
  583.             fd = access(file, 2);
  584.             *cp = '/';
  585.             if (fd == 0)
  586.                 return(1);
  587.         }
  588.         printf("%s: %s: is not removable by you\n", name, file);
  589.     }
  590.     return(0);
  591.  
  592. error1:
  593.     printf(" and is unprintable\n");
  594.     (void) close(fd);
  595.     return(-1);
  596. }
  597.  
  598. /*
  599.  * itoa - integer to string conversion
  600.  */
  601. char *
  602. itoa(i)
  603.     register int i;
  604. {
  605.     static char b[10] = "########";
  606.     register char *p;
  607.  
  608.     p = &b[8];
  609.     do
  610.         *p-- = i%10 + '0';
  611.     while (i /= 10);
  612.     return(++p);
  613. }
  614.  
  615. /*
  616.  * Perform lookup for printer name or abbreviation --
  617.  */
  618. chkprinter(s)
  619.     char *s;
  620. {
  621.     int status;
  622.     char buf[BUFSIZ];
  623.     static char pbuf[BUFSIZ/2];
  624.     char *bp = pbuf;
  625.     extern char *pgetstr();
  626.  
  627.     if ((status = pgetent(buf, s)) < 0)
  628.         fatal("cannot open printer description file");
  629.     else if (status == 0)
  630.         fatal("%s: unknown printer", s);
  631.     if ((SD = pgetstr("sd", &bp)) == NULL)
  632.         SD = DEFSPOOL;
  633.     if ((LO = pgetstr("lo", &bp)) == NULL)
  634.         LO = DEFLOCK;
  635.     RG = pgetstr("rg", &bp);
  636.     if ((MX = pgetnum("mx")) < 0)
  637.         MX = DEFMX;
  638.     if ((MC = pgetnum("mc")) < 0)
  639.         MC = DEFMAXCOPIES;
  640.     if ((DU = pgetnum("du")) < 0)
  641.         DU = DEFUID;
  642.     SC = pgetflag("sc");
  643. }
  644.  
  645. /*
  646.  * Make the temp files.
  647.  */
  648. mktemps()
  649. {
  650.     register int c, len, fd, n;
  651.     register char *cp;
  652.     char buf[BUFSIZ];
  653.     char *mktemp();
  654.  
  655.     (void) sprintf(buf, "%s/.seq", SD);
  656.     if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) {
  657.         printf("%s: cannot create %s\n", name, buf);
  658.         exit(1);
  659.     }
  660.     if (flock(fd, LOCK_EX)) {
  661.         printf("%s: cannot lock %s\n", name, buf);
  662.         exit(1);
  663.     }
  664.     n = 0;
  665.     if ((len = read(fd, buf, sizeof(buf))) > 0) {
  666.         for (cp = buf; len--; ) {
  667.             if (*cp < '0' || *cp > '9')
  668.                 break;
  669.             n = n * 10 + (*cp++ - '0');
  670.         }
  671.     }
  672.     len = strlen(SD) + strlen(host) + 8;
  673.     tfname = mktemp("tf", n, len);
  674.     cfname = mktemp("cf", n, len);
  675.     dfname = mktemp("df", n, len);
  676.     inchar = strlen(SD) + 3;
  677.     n = (n + 1) % 1000;
  678.     (void) lseek(fd, 0L, 0);
  679.     sprintf(buf, "%03d\n", n);
  680.     (void) write(fd, buf, strlen(buf));
  681.     (void) close(fd);    /* unlocks as well */
  682. }
  683.  
  684. /*
  685.  * Make a temp file name.
  686.  */
  687. char *
  688. mktemp(id, num, len)
  689.     char    *id;
  690.     int    num, len;
  691. {
  692.     register char *s;
  693.     extern char *malloc();
  694.  
  695.     if ((s = malloc(len)) == NULL)
  696.         fatal("out of memory");
  697.     (void) sprintf(s, "%s/%sA%03d%s", SD, id, num, host);
  698.     return(s);
  699. }
  700.  
  701. /*VARARGS1*/
  702. fatal(msg, a1, a2, a3)
  703.     char *msg;
  704. {
  705.     printf("%s: ", name);
  706.     printf(msg, a1, a2, a3);
  707.     putchar('\n');
  708.     exit(1);
  709. }
  710. @
  711.